import copy
import time
import numpy as np
import random
from str_color import bcolors

__RED__ = 1
__BLUE__ = 2

class Board:
    """
    该模组是本游戏的底层数据结构, line代表点格棋的边, box代表围起来的格子, 向外提供一些打印和操作的接口
    """

    def __init__(self, **kw) -> None:
        if 'not_init' in kw and kw['not_init']:
            return
        self.line = np.zeros((2, 6, 5)).astype(int)
        self.box = np.zeros((5, 5)).astype(int)

    # 步伐生成器
    def set_line(self, current_player, dir, x, y):
        if self.line[dir][x][y] == 0:
            self.line[dir][x][y] = current_player
            return 1
        else:
            return -1

    # 打印数据
    def print_box(self):
        for i in range(5):
            for j in range(5):
                print(int(self.box[i][j]), end=" ")
            print()

    def print_line(self):
        print(self.line)

    # 打印行
    def print_row(self):
        print('行状况: ')
        for i in range(6):
            for j in range(5):
                print(int(self.line[0][i][j]), end=' ')
            print()
        print('---------------------')

    # 打印列
    def print_col(self):
        print('列状况: ')
        for i in range(5):
            for j in range(6):
                print(int(self.line[1][j][i]), end=" ")
            print()
        print('---------------------')

    def check_box(self, current_player):
        """
        检查是否捕获格子
        """
        score = 0
        for i in range(5):
            for j in range(5):
                if self.box[i][j] != 0:
                    continue
                if self.line[0][i][j] != 0 and self.line[0][i + 1][j] != 0 and self.line[1][j][i] != 0 and \
                        self.line[1][j + 1][i] != 0:
                    self.box[i][j] = current_player
                    score += 1
        return score

    def get_available_step(self, **kw):
        """
        得到可走的步数, 如果is_shuffle = True
        返回是乱序
        Returns:
            list[tuple]: 可走的位置
        """
        ret = []
        for i in range(0, 6):
            for j in range(0, 5):
                if self.line[0][i][j] == 0:
                    ret.append((0, i, j))
                if self.line[1][i][j] == 0:
                    ret.append((1, i, j))
        if 'is_shuffle' in kw and kw['is_shuffle']:
            random.shuffle(ret)
        return ret

    def refresh_box(self):
        """
        刷新棋盘, 与撤销操作配合使用
        """
        for i in range(5):
            for j in range(5):
                if self.box[i][j] == 0:
                    continue
                if self.line[0][i][j] == 0 or self.line[0][i + 1][j] == 0 or self.line[1][j][i] == 0 or \
                        self.line[1][j + 1][i] == 0:
                    self.box[i][j] = 0

    def reset_board(self):
        """
        重新设置棋盘, 全清空
        """
        for i in range(5):
            for j in range(5):
                self.box[i][j] = 0

        for i in range(6):
            for j in range(5):
                self.line[0][i][j] = 0
                self.line[0][i][j] = 0

    def get_captured_line(self, i: int, j: int):
        """"
        获取当前格子的全部已经被占领的边的坐标
        传入的格子坐标
        """
        ret = []
        if self.box[i][j] != 0:
            return ret
        if self.line[0][i][j] != 0:
            ret.append((0, i, j))
        if self.line[0][i+1][j] != 0:
            ret.append((0, i+1, j))
        if self.line[1][j][i] != 0:
            ret.append((1, j, i))
        if self.line[1][j+1][i] != 0:
            ret.append((1, j+1, i))
        return ret

    def get_clone(self):
        clone = Board(not_init=True)
        clone.line = self.line.copy()
        clone.box = self.box.copy()
        return clone

    def get_box_count(self, nSides: int) -> int:
        """统计有n条边的格子

        Args:
            nSides (int): 几条空边

        Returns:
            int: 格子数量
        """
        count = 0
        for i in range(0, 5):
            for j in range(0, 5):
                if self.get_line_count(i, j) == nSides:
                    count += 1
        return count

    def get_line_count(self, i: int, j: int):
        """统计第(i, j)号格子有几条边

        Args:
            i (int): 横坐标
            j (int): 纵坐标

        Returns:
            int: 边的数量
        """
        count = 0
        if self.line[0][i][j] != 0:
            count += 1
        if self.line[0][i + 1][j] != 0:
            count += 1
        if self.line[1][j][i] != 0:
            count += 1
        if self.line[1][j + 1][i] != 0:
            count += 1
        return count

    def get_new_board(self, owner, dir, x, y) -> "Board":
        """得到一个深拷贝的棋盘, 并且会刷新棋盘格子

        Args:
            owner (int): 所有者
            dir (int): 方向
            x (int): 坐标
            y (int): 坐标

        Returns:
            Board: 棋盘
        """
        ret = copy.deepcopy(self)
        ret.set_line(owner, dir, x, y)
        ret.check_box(owner)
        return ret
    
    
    def print_color_board(self):
        """彩色打印棋盘状态
        """
        for i in range(6):
            for j in range(5):
                if j == 4:
                    if self.line[0][i][j] == __RED__:
                        print(f'*{bcolors.FAIL}--{bcolors.RESET}*')
                    elif self.line[0][i][j] == __BLUE__:
                        print(f'*{bcolors.OKBLUE}--{bcolors.RESET}*')
                    else:
                        print('*--*')
                else:
                    if self.line[0][i][j] == __RED__:
                        print(f'*{bcolors.FAIL}--{bcolors.RESET}', end='')
                    elif self.line[0][i][j] == __BLUE__:
                        print(f'*{bcolors.OKBLUE}--{bcolors.RESET}', end='')
                    else:
                        print('*--', end='')
            if i == 5:
                continue
            for j in range(6):
                if j == 5:
                    if self.line[1][j][i] == __RED__:
                        print(f'{bcolors.FAIL}|{bcolors.RESET}', end='')
                    elif self.line[1][j][i] == __BLUE__:
                        print(f'{bcolors.OKBLUE}|{bcolors.RESET}', end='')
                    else:
                        print('|', end='')

                elif self.line[1][j][i] == __RED__:
                    print(
                        f'{bcolors.FAIL}|{bcolors.RESET}', end='')
                    if self.box[i][j] != 0 and self.box[i][j] == __RED__:
                        print(
                            f'{bcolors.FAIL}r{int(self.box[i][j])}{bcolors.RESET}', end='')
                    elif self.box[i][j] != 0 and self.box[i][j] == __BLUE__:
                        print(
                            f'{bcolors.OKBLUE}b{int(self.box[i][j])}{bcolors.RESET}', end='')
                    else:
                        print('  ', end='')

                elif self.line[1][j][i] == __BLUE__:
                    print(f'{bcolors.OKBLUE}|{bcolors.RESET}', end='')
                    if self.box[i][j] != 0 and self.box[i][j] == __RED__:
                        print(
                            f'{bcolors.FAIL}r{int(self.box[i][j])}{bcolors.RESET}', end='')
                    elif self.box[i][j] != 0 and self.box[i][j] == __BLUE__:
                        print(
                            f'{bcolors.OKBLUE}b{int(self.box[i][j])}{bcolors.RESET}', end='')
                    else:
                        print('  ', end='')
                else:
                    print('|  ', end='')
                if j == 5:
                    print()
    
    def get_score(self, player: int):
        """得到棋盘中玩家的分数

        Args:
            player (int): 玩家代表数值

        Returns:
            int: 分数
        """
        score = 0
        for i in range(5):
            for j in range(5):
                if self.box[i][j] == player:
                    score += 1
        return score
    
    def template_board(self):
        """
        得到模板残局棋盘
        """
        
        self.line = np.array([[ [2, 2, 2, 1, 2],
                                [0, 0, 0, 0, 0],
                                [1, 2, 1, 0, 2],
                                [0, 1, 2, 0, 0],
                                [0, 0, 0, 0, 0],
                                [2, 1, 1, 2, 0]],

                              [ [0, 1, 2, 1, 0],
                                [2, 0, 0, 1, 2],
                                [0, 0, 0, 0, 0],
                                [1, 2, 0, 1, 0],
                                [0, 1, 0, 2, 1],
                                [1, 0, 1, 1, 2]]]).astype(int)

        return self


if __name__ == '__main__':

    board = Board()
    # board.print_color_board()
    
    start = time.time()
    for _ in range(100000):
        board.get_box_count(2)
    print(time.time() - start)